/*********************************************************************************
 *      Copyright:  (C) HuangXiangming
 *                  All rights reserved.
 *
 *       Filename:  client.c
 *    Description:  This file is temperature reporting client
 *               
 *        Version:  1.0.0(25/04/03)
 *         Author:  Huang Xiangming <huangxiangming@gmail.com>
 *      ChangeLog:  1, Release initial version on "25/04/03 13:10:30"
 *                 
 *********************************************************************************/
#include <sys/wait.h>
#include <sys/types.h>		//socket、connect
#include <sys/socket.h>
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>		//strerror
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>		//getopt
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <pthread.h>
#include <libgen.h>

#include "get_data.h"
#include "sqlite_client.h"
#include "socket.h"
#include "logger.h"
#include "proc.h"

#define PROG_VERSION            "v1.0.0"
#define PIDFILE          		"/tmp/.socketdi_h_c.pid"

static void print_usage(char *progname)
{
	printf("%s usage: \n", progname);
	printf("\n%s version %s\n", progname, PROG_VERSION);
	printf("-i(--ipaddr): sepcify server IP address\n");
	printf("-p(--port): sepcify server port\n");
	printf("-h(--help): print this help information\n");
	printf("-t(--time): acquisition interval\n");
	printf("-b(--background): Enter the daemon\n");
	printf("-d(--debug): output information to stdout\n");
	printf("-s(--sn): device sequence\n");
	printf("-v(--version): print the program version\n");
	printf("-P(--Pack):Data packing format, with options json and tlv available\n");
	printf("-S(--Stop):Stop background progname\n");
	return ;
}

int main(int argc, char **argv)
{
	char              		*progname=NULL;
	int						rv = 0;
	char					*hostname = NULL;
	int						port = 0;		
	char					buf[1024];
	int                     ch;
	int						daemon_flag = 0;
	int						report_flag = 0;
	int						sn = 1;
	int              		timeset = 30;       //默认上报时间间隔30s
	int						len = 0;

	char					*logfile = "client.log";
	char					loglevel = LOG_LEVEL_INFO;
	
	pack_proc_t          	pack_proc = pack_data;		//pack_data_json/tlv
	pack_t					data;
	socket_t				sock;

	struct option 			opts[] = {
		{"ipaddr", required_argument, NULL, 'i'},		
		{"port", required_argument, NULL, 'p'},			
		{"help", no_argument, NULL, 'h'},
		{"time", required_argument, NULL, 't'},
		{"background", no_argument, NULL, 'b'},
		{"debug", no_argument, NULL, 'd'},
		{"sn", required_argument, NULL, 's'},
		{"version", no_argument, NULL, 'v'},
		{"Pack", required_argument, NULL, 'P'},
		{"Stop", no_argument, NULL, 'S'},
		{NULL, 0, NULL, 0}
		
	};

	progname = (char *)basename(argv[0]);

	//命令行解析
	while ((ch = getopt_long(argc, argv, "i:p:ht:bds:vP:S", opts, NULL)) != -1)
	{
		switch (ch)
		{
			case 'i':
					hostname = optarg;
					break;

			case 'p':
					port = atoi(optarg);
					break;

			case 'h':
					print_usage(argv[0]);
					return 0;
			case 't':
					timeset = atoi(optarg);
					break;
			case 'b':
					daemon_flag = 1;
					break;
			case 'd':
					logfile = "stdout";
					loglevel = LOG_LEVEL_DEBUG;
					break;
			case 's':
					sn = atoi(optarg);
					break;
			case 'v':                                                  
					printf("%s version %s\n", progname, PROG_VERSION);                                   
					return 0;   

			case 'P':
					if ( strcmp(optarg, "json") == 0 )
					{
						pack_proc = pack_data_json;
					}
					else if ( strcmp(optarg, "tlv") == 0 )
					{
						pack_proc = pack_data_tlv;
					} 
					else
					{
						print_usage(argv[0]);
					}
					break;

			case 'S':
					stop_background_running(PIDFILE);
					return 0;

			default:
					print_usage(argv[0]);
					return 0;
		}
	}

	//socket初始化
	if ( !socket_init(&sock, hostname, port) )
	{
		print_usage(argv[0]);
		return -1;
	}

	//安装信号
	install_signal(timeset);

	//日志初始化
	if ( logger_init(logfile, loglevel) < 0)
	{
		fprintf(stderr, "initial logger system failure\n");
		return -1;	//成功返回0，出错返回非零整数
	}  

	//后台运行
	if ( !set_background_running(daemon_flag, PIDFILE) )
	{
		goto Cleanup;
	}

	//获取序列号
	get_devid(data.id, sizeof(data.id)-1, sn);

	//数据库初始化
	if ( sqlite_init(data.id) < 0)
	{
		return -1;
	}
	
	while( ! g_signal.stop )
	{
		report_flag = 0;	//上报标志(1上报)

		//获取温度、时间、序列号
		if ( g_signal.alarm_flag == 1 )
		{
			get_data(&data);
			report_flag = 1;
			g_signal.alarm_flag = 0;
		}

		//判断连接状态、服务器连接
		if ( !socket_diag(&sock) )
		{	
			log_debug("Server disconnected，attempting to connect...\n");
			(void)socket_connect(&sock);
		}

		//socket断开：如果采样时间到，将数据存入数据库	
		if ( !sock.connected ) 
		{   
			if ( report_flag )
			{
				log_info("Insert data into client sqlite...\n");
				(void)sqlite_inset(&data);
			}
			continue;
		} 

		//socket连接：采样时间到，上报数据；2.采样时间没到，同步数据库数据到服务器
		if( report_flag )
		{
			log_info("sent data to server...\n");
		
			len = pack_proc(&data, (uint8_t *)buf, sizeof(buf));
			if ( len <= 0 )
			{
				log_error("pack data failure\n");
				g_signal.alarm_flag = 1;	//重新获取数据
				continue;
			}

			(void)socket_write(&sock, buf, len);
			if ( !socket_diag(&sock) )
			{
				log_info("Server disconnected, insert data into client sqlite...\n");
				(void)sqlite_inset(&data);
				continue;
			} 
		}

		if( get_database_1st_record(&data) )
		{
			log_info("sqlite database have data!will sent...\n");

			len = pack_proc(&data, (uint8_t *)buf, sizeof(buf));
			if ( len <= 0 )
			{
				log_error("pack data failure\n");
				continue;
			}

			if ( socket_write(&sock, buf, len) < 0 )
			{
				log_warn("synchronization failure\n");
				continue;
			}

			if ( !delete_record(&data) )
			{
				log_info("synchronization secessful!\n");
			}
		}
		sleep(1);
	}
		
Cleanup:
	close(sock.fd);
	logger_term();
	sqlite_close();
	unlink(PIDFILE);

	return 0;
}

